import React from 'react'
import ReactReduxContext from './ReactReduxContext'
import { bindActionCreators } from '../redux'

/**
 * 连接组件和仓库
 * @param {*} mapStateToProps 将仓库的总状态映射到类组件的 props 中
 * @param {*} mapDispatchToProps 将 派发动作函数的对象 映射到类组件的 props 中
 */
function connect(mapStateToProps, mapDispatchToProps) {
  // 接收一个需要连接 store 仓库的组件
  return function (OldComponent) { 
    return class NewComponent extends React.Component {
      static contextType = ReactReduxContext // 消费一个上下文对象

      constructor(props) {
        super(props)

      }

      // 在生命周期方法中可以访问 this.context
      componentDidMount() {
        // debugger
        const { store } = this.context // 获取上下文对象中的值
        const { getState, subscribe, dispatch } = store
        this.setState(mapStateToProps(getState())) // 调用 mapStateToProps 获取仓库中的状态 保存到当前组件的 this.state 中
        // 保存仓库中需要的订阅函数 当仓库中的状态发生变化时会自动执行订阅函数
        this.unsubscribe = subscribe(() => {
          // 当仓库中的状态发生变体后 会调用 this.setState 修改组件的状态来触发更新
          this.setState(mapStateToProps(getState()))
        })
        let dispatchProps;
        if (typeof mapDispatchToProps === 'function') { // 对象情况
          // 将仓库的 dispatch 派发函数传递进去返回一个对象 里面的每个属性函数都会派发动作修改仓库的状态
          dispatchProps = mapDispatchToProps(dispatch) 
        } else {
          // 将 mapDispatchToProps 对象的每个属性函数都调用 bindActionCreators 来绑定 dispatch
          dispatchProps = bindActionCreators(mapDispatchToProps, dispatch)
        }
        // 将对象挂载到组件上
        this.dispatchProps = dispatchProps
      }
      // 在组件将要卸载的时候取消订阅
      componentWillUnmount() {
        this.unsubscribe() // 移除订阅函数
      }

      render() {
        return <OldComponent {...this.props} {...this.state} {...this.dispatchProps}></OldComponent>
      }
    }
  }
}


export default connect
